﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Resources;
using Project.Model;
using Project;
using System.IO;
using Descriptions_DomainModel.Model;
using CommonClasses.Utility;
using CommonClasses.Model;
using EcoExtensions.Model;
using Eco.ObjectImplementation;
using CommonClasses;
namespace PlantControlExplorer
{

    public partial class PlantControlExplorer : UserControl
    {
        /// <summary>
        /// Свойства, обображаемые на компноненте Properties для ProjectData
        /// </summary>
        private PropertyTable projectProps = new PropertyTable();

        /// <summary>
        /// Свойства, обображаемые на компноненте Properties для DomainModel
        /// </summary>
        private PropertyTable dmlProps = new PropertyTable();

        /// <summary>
        /// Последние выделенные объекты на каждой вкладке
        /// </summary>
        private Object[] selectedTabPageobjects = new object[3];

        /// <summary>
        /// Отображаемые данные проекта
        /// </summary>
        private ProjectData projectData;

        /// <summary>
        /// Отображаемое описание оборудования (сцена)
        /// </summary>
        private DomainModel domainModel;

        /// <summary>
        /// Последнее выделенное звено на дереве проекта
        /// </summary>
        private TreeNode lastSelectedProjectNode = null;

        /// <summary>
        /// Служебное поле для восстановления размеров окна свойств при показе
        /// </summary>
        private int pnlPropSaveSpDist;

        /// <summary>
        /// Последнее выделенное звено на описании оборудования 2
        /// </summary>
        private TreeNode lastSelectedDM2NodeF = null;

        /// <summary>
        /// Последнее выделенное звено на описании оборудования 2
        /// </summary>
        private TreeNode lastSelectedDM2Node
        {
            get { return lastSelectedDM2NodeF; }
            set
            {
                if (lastSelectedDMNode == lastSelectedDM2Node)
                    lastSelectedDMNode = value;
                lastSelectedDM2NodeF = value;
                if (value == null)
                    toolStripButton3_Click(null, null);
                else pnlDmlTreeView2.Show();
            }
        }

        /// <summary>
        /// Последнее выделенное звено на описании оборудования 1
        /// </summary>
        private TreeNode lastSelectedDM1NodeF = null;

        /// <summary>
        /// Последнее выделенное звено на описании оборудования 1
        /// </summary>
        private TreeNode lastSelectedDM1Node
        {
            get { return lastSelectedDM1NodeF; }
            set
            {
                if (lastSelectedDMNode == lastSelectedDM1Node)
                    lastSelectedDMNode = value;
                lastSelectedDM1NodeF = value;
                if ((value != null) && (value.Tag is Node))
                    FillDomainModelTreeView2();
            }
        }

        /// <summary>
        /// Последнее выделенное звено на описаниях оборудования
        /// </summary>
        private TreeNode lastSelectedDMNode = null;

        /// <summary>
        /// Последнее выделенная функция 
        /// </summary>
        private TreeNode lastSelectedFNode = null;

        /// <summary>
        /// Служебное поле для запрета разворачивания и сворачивания узлов-документов по двойному щелчку 
        /// </summary>
        private bool mayNodeToggle = false;

        /// <summary>
        /// Список картинок для дерева проекта
        /// </summary>
        private List<Image> projectIconList = new List<Image>();


        #region Public events

        /*public delegate void tProjectItemClick(TreeNode prjItem);
        public event tProjectItemClick ProjectItemClick;*/


        /// <summary>
        /// Обработчик нажатия левой кнопкой на элемент дерева проекта
        /// </summary>
        /// <param name="item">объект дерева проекта</param>
        public delegate void tProjectItemLeftClick(object item);

        /// <summary>
        /// Событие: нажатие левой кнопкой на элемент дерева проекта
        /// </summary>
        public event tProjectItemLeftClick ProjectItemLeftClickEvent;

        /// <summary>
        /// Обработчик нажатия правой кнопкой на элемент дерева проекта
        /// </summary>
        /// <param name="item">объект дерева проекта</param>
        /// <param name="treeNode">узел на дереве проекта, соответствующий объекту</param>
        /// <param name="screenPoint">координаты щелчка</param>
        /// 
        public delegate void tProjectItemRightClick(object item, TreeNode treeNode, Point screenPoint);

        /// <summary>
        /// Событие: нажатие правой кнопкой на элемент дерева проекта
        /// </summary>
        /// 
        public event tProjectItemRightClick ProjectItemRightClickEvent;

        /// <summary>
        /// Обработчик двойного нажатия на элемент дерева проекта
        /// </summary>
        /// <param name="item">объект</param>
        /// 
        public delegate void tProjectItemDoubleClick(object item);

        /// <summary>
        /// Событие: нажатие правой кнопкой на элемент дерева проекта
        /// </summary>
        /// 
        public event tProjectItemDoubleClick ProjectItemDoubleClickEvent;

        /// <summary>
        /// Обрабочик изменения какого-либо значения в объекте структуры проекта
        /// </summary>
        /// <param name="item">элемент</param>
        /// <param name="code">параметр элемента</param>
        /// <param name="newValue">новое значение</param>
        /// 
        public delegate void tProjectItemValueChanged(object item, ProjectEventCode code, object newValue);

        /// <summary>
        /// Событие: измененилось какое-либо значение в объекте структуры проекта
        /// </summary>
        /// 
        public event tProjectItemValueChanged ProjectItemValueChangedEvent;

        /// <summary>
        /// Запрос какого-либо значения для объекта структуры проекта
        /// </summary>
        /// <param name="item">элемент</param>
        /// <param name="code">параметр элемента</param>
        /// <returns>возвращаемое значение</returns>
        /// 
        public delegate object tProjectItemValueRequested(object item, ProjectEventCode code);

        /// <summary>
        /// Событие: запрос какого-либо значения для объекта структуры проекта
        /// </summary>
        /// 
        public event tProjectItemValueRequested ProjectItemValueRequestedEvent;

        /// <summary>
        /// Перетащить одни элементы в другой
        /// </summary>
        /// <param name="items">элементы</param>
        /// <param name="targetItem">элемент, в который перетаскиваются</param>
        public delegate void tProjectItemsDragDropped(List<object> items, object targetItem);

        /// <summary>
        /// Событие: перетащить одни элементы в другой
        /// </summary>
        public event tProjectItemsDragDropped ProjectItemsDragDroppedEvent;



        /// <summary>
        /// Обработчик нажатия левой кнопкой на элемент дерева оборудования
        /// </summary>
        /// <param name="item">объект</param>
        /// 
        public delegate void tDmlItemClick(object item);

        /// <summary>
        /// Событие: нажатие левой кнопкой на элемент дерева оборудования
        /// </summary>
        /// 
        public event tDmlItemClick DmlItemClickEvent;

        /// <summary>
        /// Обработчик нажатия правой кнопкой на элемент дерева оборудования
        /// </summary>
        /// <param name="item">объект</param>
        /// 
        public delegate void tDmlItemRightClick(object item);

        /// <summary>
        /// Событие: нажатие правой кнопкой на элемент дерева оборудования
        /// </summary>
        /// 
        public event tDmlItemRightClick DmlItemRightClickEvent;

        /// <summary>
        /// Обработчик двойного нажатия на элемент дерева оборудования
        /// </summary>
        /// <param name="item">объект</param>
        /// 
        public delegate void tDmlItemDoubleClick(object item);

        /// <summary>
        /// Событие: нажатие правой кнопкой на элемент дерева оборудования
        /// </summary>
        /// 
        public event tDmlItemDoubleClick DmlItemDoubleClickEvent;

        /// <summary>
        /// Обрабочик изменения какого-либо значения в объекте описания оборудования
        /// </summary>
        /// <param name="item">элемент</param>
        /// <param name="code">параметр элемента</param>
        /// <param name="newValue">новое значение</param>
        /// 
        public delegate void tDmlItemValueChanged(object item, DmlEventCode code, object newValue);

        /// <summary>
        /// Событие: измененилось какое-либо значение в объекте описания оборудования
        /// </summary>
        /// 
        public event tDmlItemValueChanged DmlItemValueChangedEvent;

        /// <summary>
        /// Запрос какого-либо значения для объекта описания оборудования
        /// </summary>
        /// <param name="item">элемент</param>
        /// <param name="code">параметр элемента</param>
        /// <returns>возвращаемое значение</returns>
        /// 
        public delegate object tDmlItemValueRequested(object item, DmlEventCode code);

        /// <summary>
        /// Событие: Запрос какого-либо значения для объекта описания оборудования
        /// </summary>
        /// 
        public event tDmlItemValueRequested DmlItemValueRequestedEvent;
        #endregion


        #region Invokers of public events

        /// <summary>
        /// Вызвать событие: нажатие левой кнопкой на элемент дерева проекта
        /// </summary>
        /// <param name="item">объект дерева проекта</param>
        private void ProjectItemLeftClick(object item)
        {
            if (ProjectItemLeftClickEvent != null)
                ProjectItemLeftClickEvent(item);
        }

        /// <summary>
        /// Вызвать событие: нажатие правой кнопкой на элемент дерева проекта
        /// </summary>
        /// <param name="item">объект</param>
        /// <param name="treeNode">узел на дереве проекта, соответствующий объекту</param>
        /// <param name="screenPoint">координаты щелчка на экране</param>
        /// 
        private void ProjectItemRightClick(object item, TreeNode treeNode, Point screenPoint)
        {
            if (ProjectItemRightClickEvent != null)
                ProjectItemRightClickEvent(item, treeNode, screenPoint);
        }

        /// <summary>
        /// Вызвать событие: двойное нажатие левой кнопкой на элемент дерева проекта
        /// </summary>
        /// <param name="item">объект</param>
        private void ProjectItemDoubleClick(object item)
        {
            if (ProjectItemDoubleClickEvent != null)
                ProjectItemDoubleClickEvent(item);
        }

        /// <summary>
        /// Вызвать событие: измененилось какое-либо значение в объекте структуры проекта
        /// </summary>
        /// <param name="item">элемент</param>
        /// <param name="code">параметр элемента</param>
        /// <param name="newValue">новое значение</param>
        /// 
        private void ProjectItemValueChanged(object item, ProjectEventCode code, object newValue)
        {
            if (ProjectItemValueChangedEvent != null)
                ProjectItemValueChangedEvent(item, code, newValue);
        }

        /// <summary>
        /// Вызвать событие: запрос какого-либо значения для объекта структуры проекта
        /// </summary>
        /// <param name="item">элемент</param>
        /// <param name="code">параметр элемента</param>
        /// <returns>возвращаемое значение</returns>
        /// 
        private object ProjectItemValueRequested(object item, ProjectEventCode code)
        {
            if (ProjectItemValueRequestedEvent != null)
                return ProjectItemValueRequestedEvent(item, code);
            else return null;
        }

        /// <summary>
        /// Вызвать событие: перетащить одни элементы в другой
        /// </summary>
        /// <param name="items">элементы</param>
        /// <param name="targetItem">элемент, в который перетаскиваются</param>
        private void ProjectItemsDragDrooped(List<object> items, object targetItem)
        {
            if (ProjectItemsDragDroppedEvent != null)
                ProjectItemsDragDroppedEvent(items, targetItem);
        }



        /// <summary>
        /// Вызвать событие: нажатие левой кнопкой на элемент дерева оборудования
        /// </summary>
        /// <param name="item">объект</param>
        private void DmlItemClick(object item)
        {
            if (DmlItemClickEvent != null)
                DmlItemClickEvent(item);
        }

        /// <summary>
        /// Вызвать событие: нажатие правой кнопкой на элемент дерева оборудования
        /// </summary>
        /// <param name="item">объект</param>
        private void DmlItemRightClick(object item)
        {
            if (DmlItemRightClickEvent != null)
                DmlItemRightClickEvent(item);
        }

        /// <summary>
        /// Вызвать событие: двойное нажатие левой кнопкой на элемент дерева оборудования
        /// </summary>
        /// <param name="item">объект</param>
        /// 
        private void DmlItemDoubleClick(object item)
        {
            if (DmlItemDoubleClickEvent != null)
                DmlItemDoubleClickEvent(item);
        }

        /// <summary>
        /// Вызвать событие: измененилось какое-либо значение в объекте описания оборудования
        /// </summary>
        /// <param name="item">элемент</param>
        /// <param name="code">параметр элемента</param>
        /// <param name="newValue">новое значение</param>
        /// 
        private void DmlItemValueChanged(object item, DmlEventCode code, object newValue)
        {
            if (DmlItemValueChangedEvent != null)
                DmlItemValueChangedEvent(item, code, newValue);
        }

        /// <summary>
        /// Вызвать событие: запрос какого-либо значения для объекта описания оборудования
        /// </summary>
        /// <param name="item">элемент</param>
        /// <param name="code">параметр элемента</param>
        /// <returns>возвращаемое значение</returns>
        /// 
        private object DmlItemValueRequested(object item, DmlEventCode code)
        {
            if (DmlItemValueRequestedEvent != null)
                return DmlItemValueRequestedEvent(item, code);
            else return null;
        }



        #endregion


        /// <summary>
        /// Конструктор
        /// </summary>
        public PlantControlExplorer()
        {
            InitializeComponent();

            pnlPropSaveSpDist = splitContainer1.SplitterDistance;

            toolStripButton3_Click(null, null);

            ProjectTreeView.Leave += new EventHandler(PrjTreeView_Leave);
            ProjectTreeView.Enter += new EventHandler(PrjTreeView_Enter);

            projectProps.SetValue += new PropertySpecEventHandler(this.ProjectProp_SetValue);
            projectProps.GetValue += new PropertySpecEventHandler(this.ProjectProp_GetValue);

            //dmlProps.SetValue += new PropertySpecEventHandler(this.DmlProp_SetValue);
            //dmlProps.GetValue += new PropertySpecEventHandler(this.DmlProp_GetValue);

            projectIconList.Add(global::PlantControlExplorer.Properties.Resources.Folder_Open);
            projectIconList.Add(global::PlantControlExplorer.Properties.Resources.Folder_Closed);
            projectIconList.Add(global::PlantControlExplorer.Properties.Resources.Document);

            ProjectTreeView.ImageList = new ImageList();
            projectIconList.ForEach(img =>
            {
                if (img is Bitmap)
                    (img as Bitmap).MakeTransparent((img as Bitmap).GetPixel(0, 0));
                ProjectTreeView.ImageList.Images.Add(img);
            });

            //ProjectTreeView.ImageList.TransparentColor = Color.FromArgb(255, 128, 0, 128);
            // Color.FromArgb(255, 128, 0, 128);
            // (ProjectTreeView.ImageList.Images[0] as Bitmap).GetPixel(0, 0); 
            foreach (Bitmap bmp in ProjectTreeView.ImageList.Images)
            {
                // = bmp.GetPixel(1, 1);
                //bmp.MakeTransparent(bmp.GetPixel(1,1));
            }
        }


        /// <summary>
        /// Выполнить действия при загрузке нового проекта
        /// </summary>
        public void OnProjectLoaded()
        {
            return;
        }


        /// <summary>
        /// Выполнить действия при выгрузке проекта
        /// </summary>
        public void OnProjectClosed()
        {
            selectedTabPageobjects[0] = null;
            selectedTabPageobjects[1] = null;
            lastSelectedDM1Node = null;
            lastSelectedProjectNode = null;
            Properties.SelectedObject = null;
            ClearProjectTreeView();
            ClearDomainTreeView();
        }


        #region Filling and clearing trees methods

        /// <summary>
        /// Заполнить дерево проекта по имеющимся данным проекта
        /// </summary>
        /// <param name="projectData">данные проекта</param>
        public void FillProjectTreeView(ProjectData projectData)
        {
            this.projectData = projectData;
            ClearProjectTreeView();

            if (projectData == null) return;

            if (lastSelectedProjectNode != null)
            {
                lastSelectedProjectNode.Text = "1234567898765432";
                lastSelectedProjectNode.Nodes.Clear();
            }

            if ((lastSelectedProjectNode != null) && (lastSelectedProjectNode.Tag == this.projectData))
            {
                lastSelectedProjectNode.Text = projectData.Name;
                ProjectTreeView.Nodes.Add(lastSelectedProjectNode);
                FillVirtFilder(projectData.ProjectFolder, lastSelectedProjectNode);
            }
            else
            {
                TreeNode node = new TreeNode(projectData.Name);
                node.ImageIndex = 1;
                node.SelectedImageIndex = 1;
                node.Tag = projectData;
                ProjectTreeView.Nodes.Add(node);
                FillVirtFilder(projectData.ProjectFolder, node);
            }

            if (lastSelectedProjectNode != null)
            {
                // если теперь такого звена нет
                if (lastSelectedProjectNode.Text == "1234567898765432")
                {
                    lastSelectedProjectNode = null;
                    Properties.SelectedObject = null;
                }
                else PrjTreeView_AfterSelect(this, new TreeViewEventArgs(lastSelectedProjectNode));

            }

            mayNodeToggle = true;
            ExpandExceptDocuments();
            //ProjectTreeView.ExpandAll();
            mayNodeToggle = false;
        }

        /// <summary>
        /// Заполнить узел дерева элементами документа
        /// </summary>
        /// <param name="document"></param>
        /// <param name="node"></param>
        private void FillDocument(DocumentInfo document, TreeNode node)
        {
            foreach (EcoObject element in document.DocElements)
            {
                var elem = element.Object as IDocStructElement;
                TreeNode newNode = new TreeNode(elem.Name);

                if (!projectIconList.Contains(elem.Icon))
                {
                    projectIconList.Add(elem.Icon);
                    ProjectTreeView.ImageList.Images.Add(elem.Icon);
                }
                int imageIndex = projectIconList.IndexOf(elem.Icon);
                newNode.SelectedImageIndex = imageIndex;
                newNode.ImageIndex = imageIndex;
                newNode.Tag = elem;
                node.Nodes.Add(newNode);
            }
        }

        /// <summary>
        /// Заполнить узел дерева элементами виртуальной папки проекта
        /// </summary>
        /// <param name="virtFolder"></param>
        /// <param name="node"></param>
        private void FillVirtFilder(VirtFolder virtFolder, TreeNode node)
        {
            // добавляем подпапки
            foreach (VirtFolder vfolder in virtFolder.SubFolders)
            {
                if ((lastSelectedProjectNode != null) && (lastSelectedProjectNode.Tag == vfolder))
                {
                    lastSelectedProjectNode.Text = vfolder.Name;
                    FillVirtFilder(vfolder, lastSelectedProjectNode);
                    node.Nodes.Add(lastSelectedProjectNode);
                }
                else
                {
                    TreeNode newNode = new TreeNode(vfolder.Name);
                    FillVirtFilder(vfolder, newNode);
                    newNode.SelectedImageIndex = 1;
                    newNode.ImageIndex = 1;
                    newNode.Tag = vfolder;
                    node.Nodes.Add(newNode);
                }
            }

            // добавляем документы
            foreach (DocumentInfo doc in virtFolder.Documents)
            {
                if ((lastSelectedProjectNode != null) && (lastSelectedProjectNode.Tag == doc))
                {
                    lastSelectedProjectNode.Text = Path.GetFileNameWithoutExtension(doc.DocumentPath);
                    node.Nodes.Add(lastSelectedProjectNode);
                    FillDocument(doc, lastSelectedProjectNode);
                }
                else
                {
                    TreeNode newNode = new TreeNode(Path.GetFileNameWithoutExtension(doc.DocumentPath));
                    newNode.SelectedImageIndex = 2;
                    newNode.ImageIndex = 2;
                    newNode.Tag = doc;
                    node.Nodes.Add(newNode);
                    FillDocument(doc, newNode);
                }


            }
        }

        /// <summary>
        /// Заполнить дерево сцены
        /// </summary>
        /// <param name="domainModel">описание оборудования</param>
        public void FillDomainModelTreeView(DomainModel domainModel)
        {
            ClearDomainTreeView();

            this.domainModel = domainModel;

            lastSelectedDM1Node = null;

            TreeNode node = new TreeNode("Сцена");
            node.Tag = domainModel;
            DomainModelTreeView.Nodes.Add(node);
            foreach (NodeGroup nodeGroup in domainModel.NodeGroups)
            {
                if (nodeGroup.Type != "System")
                {
                    TreeNode nod = new TreeNode(nodeGroup.Name);
                    FillNodeGroup(nodeGroup, nod);
                    nod.Tag = nodeGroup;
                    node.Nodes.Add(nod);
                }
            }

            mayNodeToggle = true;
            DomainModelTreeView.ExpandAll();
            mayNodeToggle = false;

            FillDomainModelTreeView2();
            FillFunctionTreeView();
        }

        /// <summary>
        /// Заполнить дерево сцены
        /// </summary>
        /// <param name="domainModel">описание оборудования</param>
        public void FillFunctionTreeView()
        {
            ClearFunctionTreeView();

            lastSelectedFNode = null;

            TreeNode node = new TreeNode("Функции");
            node.Tag = null;
            FunctionTreeView.Nodes.Add(node);
            foreach (var function in domainModel.FunctionLibrary.Functions)
            {
                TreeNode nod = new TreeNode(function.Name);
                nod.Tag = function;
                node.Nodes.Add(nod);
            }

            mayNodeToggle = true;
            FunctionTreeView.ExpandAll();
            mayNodeToggle = false;
        }


        /// <summary>
        /// Заполнить дополнительное дерево сцены
        /// </summary>
        public void FillDomainModelTreeView2()
        {
            ClearDomainTreeView2();

            if ((lastSelectedDM1Node != null) && (lastSelectedDM1Node.Tag is Node))
            {
                pnlDmlTreeView2.Show();

                TreeNode methodsNode = new TreeNode("Методы");
                methodsNode.Tag = (lastSelectedDM1Node.Tag as Node).Methods;
                foreach (Method m in (lastSelectedDM1Node.Tag as Node).Methods)
                {
                    TreeNode nod = new TreeNode(m.Name);
                    nod.Tag = m;
                    methodsNode.Nodes.Add(nod);
                }
                DomainModelTreeView2.Nodes.Add(methodsNode);

                TreeNode statesNode = new TreeNode("Состояния");
                statesNode.Tag = (lastSelectedDM1Node.Tag as Node).NamedStates;
                foreach (NamedState st in (lastSelectedDM1Node.Tag as Node).NamedStates)
                {
                    TreeNode nod = new TreeNode(st.Name);
                    nod.Tag = st;
                    statesNode.Nodes.Add(nod);
                }
                DomainModelTreeView2.Nodes.Add(statesNode);
            }
            else toolStripButton3_Click(null, null);

            DomainModelTreeView2.ExpandAll();
        }

        /// <summary>
        /// Заполнить узел дерева по узлу описания оборудования
        /// </summary>
        /// <param name="dmNode">узел описания оборудования</param>
        /// <param name="node">узел, в который добавлять</param>
        private void FillNode(Node dmNode, TreeNode node)
        {
            foreach (Node n in dmNode.Nodes)
            {
                TreeNode nod = new TreeNode(n.Name);
                FillNode(n, nod);
                nod.Tag = n;
                node.Nodes.Add(nod);
            }
        }

        /// <summary>
        /// Заполнить узел дерева по группе узлов описания оборудования
        /// </summary>
        /// <param name="nodeGroup">группа узлов</param>
        /// <param name="node">узел дерева, в кот. добавлять группу</param>
        private void FillNodeGroup(NodeGroup nodeGroup, TreeNode node)
        {
            foreach (Node n in nodeGroup.Nodes)
            {
                TreeNode nod = new TreeNode(n.Name);
                FillNode(n, nod);
                nod.Tag = n;
                node.Nodes.Add(nod);
            }
        }


        /// <summary>
        /// Очистить дерево проекта
        /// </summary>
        public void ClearProjectTreeView()
        {
            ProjectTreeView.Nodes.Clear();
            ProjectTreeView.Invalidate(true);
        }


        /// <summary>
        /// Очистить дерево сцены
        /// </summary>
        public void ClearDomainTreeView()
        {
            DomainModelTreeView.Nodes.Clear();
            DomainModelTreeView.Invalidate(true);
        }

        /// <summary>
        /// Очистить дерево функций
        /// </summary>
        public void ClearFunctionTreeView()
        {
            FunctionTreeView.Nodes.Clear();
            FunctionTreeView.Invalidate(true);
        }

        /// <summary>
        /// Очистить дерево сцены 2
        /// </summary>
        public void ClearDomainTreeView2()
        {
            DomainModelTreeView2.Nodes.Clear();
            DomainModelTreeView2.Invalidate(true);
        }
        #endregion


        #region Event handlers of visual components' events

        /// <summary>
        /// Обработчик выделения узла дерева проекта
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">TreeViewEventArgs</param>
        /// 
        private void PrjTreeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            lastSelectedProjectNode = e.Node;
            if (e.Node.Tag is ProjectData)
            {
                projectProps.Properties.Clear();
                PropertyTable projectDataProps = new PropertyTable();
                projectDataProps.GetValue += new PropertySpecEventHandler(ProjectProp_GetValue);
                projectDataProps.SetValue += new PropertySpecEventHandler(ProjectProp_SetValue);

                PropertySpec ps;

                ps = new PropertySpec("Файл сцены", typeof(string), "Описание проекта", "Путь до файла описания оборудования");
                ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                projectDataProps.Properties.Add(ps);


                ps = new PropertySpec("Название", typeof(string), "Описание проекта", "Название проекта");
                projectDataProps.Properties.Add(ps);

                ps = new PropertySpec("Путь", typeof(string), "Описание проекта", "Путь до папки с файлом проекта");
                ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                projectDataProps.Properties.Add(ps);

                ps = new PropertySpec("Тип", typeof(string), "Описание проекта", "Тип проекта", null, "", typeof(ProjectTypeConverter));
                ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                projectDataProps.Properties.Add(ps);

                Properties.SelectedObject = projectDataProps;
            }
            else if (e.Node.Tag is VirtFolder)
            {
                PropertyTable virtFolderProps = new PropertyTable();
                virtFolderProps.GetValue += new PropertySpecEventHandler(ProjectProp_GetValue);
                virtFolderProps.SetValue += new PropertySpecEventHandler(ProjectProp_SetValue);

                PropertySpec ps;

                ps = new PropertySpec("Название", typeof(string), "Описание раздела", "Название раздела");
                virtFolderProps.Properties.Add(ps);

                Properties.SelectedObject = virtFolderProps;
            }
            else if (e.Node.Tag is DocumentInfo)
            {
                projectProps.Properties.Clear();
                PropertySpec ps;

                ps = new PropertySpec("Тип", typeof(string), "Описание документа", "Тип документа");
                ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                projectProps.Properties.Add(ps);

                ps = new PropertySpec("Название", typeof(string), "Описание документа", "Имя файла документа без расширения");
                projectProps.Properties.Add(ps);

                ps = new PropertySpec("Путь", typeof(string), "Описание документа", "Путь до папки с файлом документа");
                ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                projectProps.Properties.Add(ps);

                ps = new PropertySpec("Компилируется", typeof(bool), "Описание документа", "Будут ли данные документа переводится в программу", this.ProjectItemValueRequested(e.Node.Tag, ProjectEventCode.IsDocCompiled), "", typeof(BooleanTypeConverter));
                if (!((DocumentInfo)e.Node.Tag).DocumentType.IsCompilable)
                    ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                projectProps.Properties.Add(ps);
                Properties.SelectedObject = projectProps;
            }
            else if (e.Node.Tag is IDocStructElement)
            {
                Properties.SelectedObject = (e.Node.Tag as IDocStructElement).PropertyTable.Object;
            }
            else Properties.SelectedObject = e.Node.Tag;

        }

        /// <summary>
        /// Обработчик нажатия на узел дерева проекта
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">TreeNodeMouseClickEventArgs</param>
        /// 
        private void PrjTreeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                ProjectTreeView.SelectedNode = e.Node;
                ProjectItemRightClick(e.Node.Tag, e.Node, PointToScreen(e.Location));
            }
            else if (e.Button == MouseButtons.Left)
            {
                //Point pnt = Cursor.Position;
                //pnt = treeView1.PointToClient(pnt);
                TreeNode nd = ProjectTreeView.GetNodeAt(e.Location);
                ProjectTreeView.SelectedNode = nd;
                if (nd != null)
                {
                    Rectangle boundsWithIcon = nd.Bounds;
                    boundsWithIcon.X -= 16;
                    if ((!boundsWithIcon.Contains(e.Location)) && (e.Location.X < boundsWithIcon.X))
                    {
                        mayNodeToggle = true;
                        e.Node.Toggle();
                        mayNodeToggle = false;
                    }
                }

                ProjectItemLeftClick(e.Node.Tag);
            }
        }

        /// <summary>
        /// Обработчик двойного нажатия на узел дерева проекта
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">TreeNodeMouseClickEventArgs</param>
        /// 
        private void PrjTreeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                //Point pnt = Cursor.Position;
                //pnt = treeView1.PointToClient(pnt);
                TreeNode nd = ProjectTreeView.GetNodeAt(e.Location);
                if (nd != null)
                {
                    Rectangle boundsWithIcon = nd.Bounds;
                    boundsWithIcon.X -= 16;
                    if (boundsWithIcon.Contains(e.Location))
                    {
                        if (!(e.Node.Tag is DocumentInfo))
                        {
                            mayNodeToggle = true;
                            e.Node.Toggle();
                            mayNodeToggle = false;
                        }
                    }
                }
                ProjectItemDoubleClick(e.Node);
            }
        }


        /// <summary>
        /// Обработчик выделения узла дерева оборудования
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">TreeViewEventArgs</param>
        private void DmlTreeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (sender == this.DomainModelTreeView)
                lastSelectedDM1Node = e.Node;
            else if (sender == this.DomainModelTreeView)
                lastSelectedDM2Node = e.Node;
            lastSelectedDMNode = e.Node;
            if (e.Node.Tag is NodeGroup)
            {
                dmlProps.Properties.Clear();
                PropertySpec ps;

                //сейчас типов устройств нет
                //ps = new PropertySpec("Тип", typeof(string), "Описание устройства", "", ((NodeGroup)e.Node.Tag).Type.Name);
                //ps.Attributes = new Attribute[] {ReadOnlyAttribute.Yes};
                //DmlProp.Properties.Add(ps);

                ps = new PropertySpec("Имя", typeof(string), "Описание устройства", "", ((NodeGroup)e.Node.Tag).Name);
                ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                dmlProps.Properties.Add(ps);

                ps = new PropertySpec("Комментарии", typeof(string), "Описание устройства", "", ((NodeGroup)e.Node.Tag).Comments);
                ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes};
                dmlProps.Properties.Add(ps);

                //DmlProp["Тип"] = ((NodeGroup)e.Node.Tag).Type.Name;
                dmlProps["Комментарии"] = ((NodeGroup)e.Node.Tag).Comments;
                dmlProps["Имя"] = ((NodeGroup)e.Node.Tag).Name;

                Properties.SelectedObject = dmlProps;
            }
            else
                if (e.Node.Tag is Node)
                {
                    dmlProps.Properties.Clear();
                    PropertySpec ps;

                    ps = new PropertySpec("Имя", typeof(string), "Описание узла", null, ((Node)e.Node.Tag).Name);
                    ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                    dmlProps.Properties.Add(ps);


                    ps = new PropertySpec("Комментарии", typeof(string), "Описание узла", null, (((Node)e.Node.Tag).Comments));
                    ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                    dmlProps.Properties.Add(ps);

                    ps = new PropertySpec("Имя в программе", typeof(string), "Описание узла", null, "");
                    ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                    dmlProps.Properties.Add(ps);

                    dmlProps["Имя"] = ((Node)e.Node.Tag).Name;
                    dmlProps["Комментарии"] = ((Node)e.Node.Tag).Comments;
                    dmlProps["Имя в программе"] = ChangePathOnPoints(e.Node.FullPath);

                    foreach (Method m in ((Node)e.Node.Tag).Methods)
                    {
                        dmlProps[m.Name] = (m.Comments != null) ? m.Comments : "";
                    }

                    foreach (NamedState state in ((Node)e.Node.Tag).NamedStates)
                    {
                        dmlProps[state.Name] = (state.Comments != null) ? state.Comments : "";
                    }
                    Properties.SelectedObject = dmlProps;

                }
                else if ((e.Node.Tag is ObjectListAdapter<Method>) || (e.Node.Tag is ObjectListAdapter<NamedState>))
                    Properties.SelectedObject = null;
                else if ((e.Node.Tag is Method))
                {
                    dmlProps.Properties.Clear();
                    PropertySpec ps;

                    ps = new PropertySpec("Комментарии", typeof(string), "Описание метода");
                    ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                    dmlProps.Properties.Add(ps);

                    ps = new PropertySpec("Имя", typeof(string), "Описание метода");
                    ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                    dmlProps.Properties.Add(ps);

                    ps = new PropertySpec("Имя в программе", typeof(string), "Описание метода", null, "");
                    ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                    dmlProps.Properties.Add(ps);

                    dmlProps["Комментарии"] = (e.Node.Tag as Method).Comments;
                    dmlProps["Имя"] = (e.Node.Tag as Method).Name;

                    TreeNode parentNode = null;
                    foreach (var rootn in DomainModelTreeView.Nodes)
                    {
                        rootn.DeepWalk("Nodes", tn =>
                            {
                                if ((((TreeNode)tn).Tag is Node) && (((TreeNode)tn).Tag as Node).Methods.Contains(e.Node.Tag as Method))
                                    parentNode = (TreeNode)tn;
                            });
                    }
                    dmlProps["Имя в программе"] = ChangePathOnPoints(parentNode.FullPath) + "." + (e.Node.Tag as Method).Name;

                    Properties.SelectedObject = dmlProps;
                }
                else if ((e.Node.Tag is NamedState))
                {
                    dmlProps.Properties.Clear();
                    PropertySpec ps;

                    ps = new PropertySpec("Комментарии", typeof(string), "Описание состояния");
                    ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                    dmlProps.Properties.Add(ps);

                    ps = new PropertySpec("Имя", typeof(string), "Описание состояния");
                    ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                    dmlProps.Properties.Add(ps);

                    ps = new PropertySpec("Имя в программе", typeof(string), "Описание состояния", null, "");
                    ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                    dmlProps.Properties.Add(ps);

                    dmlProps["Комментарии"] = (e.Node.Tag as NamedState).Comments;
                    dmlProps["Имя"] = (e.Node.Tag as NamedState).Name;
                    TreeNode parentNode = null;
                    foreach (var rootn in DomainModelTreeView.Nodes)
                    {
                        rootn.DeepWalk("Nodes", tn =>
                        {
                            if ((((TreeNode)tn).Tag is Node) && (((TreeNode)tn).Tag as Node).NamedStates.Contains(e.Node.Tag as NamedState))
                                parentNode = (TreeNode)tn;
                        });
                    }
                    dmlProps["Имя в программе"] = ChangePathOnPoints(parentNode.FullPath) + "." + (e.Node.Tag as NamedState).Name;

                    Properties.SelectedObject = dmlProps;
                }
                else Properties.SelectedObject = e.Node.Tag;
        }

        /// <summary>
        /// Обработчик выделения узла дерева функций
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">TreeViewEventArgs</param>
        private void FunTreeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (sender == this.FunctionTreeView)
                lastSelectedFNode = e.Node;

            if (e.Node.Tag is Function)
            {

                var selFunc = (Function)e.Node.Tag;

                dmlProps.Properties.Clear();
                PropertySpec ps;

                ps = new PropertySpec("Имя", typeof(string), "Описание функции");
                ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                dmlProps.Properties.Add(ps);

                ps = new PropertySpec("Текст на LPMED", typeof(string), "Описание функции");
                ps.Attributes = new Attribute[] { new ReadOnlyAttribute(true), new EditorAttribute(typeof(TextValueEditor), typeof(System.Drawing.Design.UITypeEditor)), new EditorBrowsableAttribute(EditorBrowsableState.Always) };
                ps.Description = "Текст функции на LPMED";
                dmlProps.Properties.Add(ps);

                foreach (var param in selFunc.Parameters)
                {
                    ps = new PropertySpec(param.Name, typeof(string), "Параметры функции");
                    ps.Attributes = new Attribute[] { ReadOnlyAttribute.Yes };
                    dmlProps.Properties.Add(ps);
                }

                dmlProps["Имя"] = selFunc.Name;
                dmlProps["Текст на LPMED"] = selFunc.Code;
                foreach (var param in selFunc.Parameters)
                    dmlProps[param.Name] = param.Comment;

                Properties.SelectedObject = dmlProps;
            }
            else Properties.SelectedObject = e.Node.Tag;
        }

        /// <summary>
        /// Обработчик нажатия на узел дерева оборудования
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">TreeNodeMouseClickEventArgs</param>
        ///
        private void DmlTreeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
                DmlItemRightClick(e.Node);
            else DmlItemClick(e.Node);
        }

        /// <summary>
        /// Обработчик двойного нажатия на узел дерева оборудования
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">TreeNodeMouseClickEventArgs</param>
        ///
        private void DmlTreeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            DmlItemDoubleClick(e.Node);
        }



        /// <summary>
        /// Обработчик выделения вкладки с деревом
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">TabControlCancelEventArgs</param>
        /// 
        private void tabControl1_Selecting(object sender, TabControlCancelEventArgs e)
        {
            if (e.TabPage.Text != "Сцена")
                lastSelectedDM2Node = null;
            Properties.SelectedObject = selectedTabPageobjects[e.TabPageIndex];
        }

        /// <summary>
        /// Обработчик снятия выделения с вкладки с деревом
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">TabControlCancelEventArgs</param>
        /// 
        private void tabControl1_Deselecting(object sender, TabControlCancelEventArgs e)
        {
            selectedTabPageobjects[e.TabPageIndex] = Properties.SelectedObject;
        }



        /// <summary>
        /// Обработчик попадания курсора на дерево проекта
        /// (нужно для визуального эффекта, иначе Properties останется отображать последний
        /// выделенный элемент, а дереве проекта его не будет видно)
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">EventArgs</param>
        private void PrjTreeView_Enter(object sender, EventArgs e)
        {
            if (lastSelectedProjectNode == null) return;

            lastSelectedProjectNode.BackColor = SystemColors.Window;
            lastSelectedProjectNode.ForeColor = SystemColors.WindowText;
        }

        /// <summary>
        /// Обработчик ухода курсора c дерева проекта
        /// (нужно для визуального эффекта, иначе Properties останется отображать последний
        /// выделенный элемент, а дереве проекта его не будет видно)
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">EventArgs</param>
        private void PrjTreeView_Leave(object sender, EventArgs e)
        {
            if (ProjectTreeView.SelectedNode == null) return;

            lastSelectedProjectNode = ProjectTreeView.SelectedNode;
            lastSelectedProjectNode.BackColor = SystemColors.Highlight;
            lastSelectedProjectNode.ForeColor = SystemColors.HighlightText;
        }

        /// <summary>
        /// Обработчик прихода курсора на дерево описания оборудования
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">EventArgs</param>
        private void DomainModelTreeView_Enter(object sender, EventArgs e)
        {
            TreeNode lastSelected = null;
            if (sender == DomainModelTreeView)
                lastSelected = lastSelectedDM1Node;
            else if (sender == DomainModelTreeView2)
                lastSelected = lastSelectedDM2Node;

            if (lastSelected == null) 
                return;

            lastSelected.BackColor = SystemColors.Window;
            lastSelected.ForeColor = SystemColors.WindowText;
        }

        /// <summary>
        /// Обработчик прихода курсора на дерево описания оборудования
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FunctionTreeView_Enter(object sender, EventArgs e)
        {
            TreeNode lastSelected = null;
            if (sender == FunctionTreeView)
                lastSelected = lastSelectedFNode;

            if (lastSelected == null)
                return;

            lastSelected.BackColor = SystemColors.Window;
            lastSelected.ForeColor = SystemColors.WindowText;
        }

        /// <summary>
        /// Обработчик ухода курсора c дерева описания оборудования
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">EventArgs</param>
        private void DomainModelTreeView_Leave(object sender, EventArgs e)
        {
            TreeNode lastSelected = null;
            if (sender == DomainModelTreeView)
                lastSelected = lastSelectedDM1Node;
            else if (sender == DomainModelTreeView2)
                lastSelected = lastSelectedDM2Node;

            if (lastSelected == null) return;

            lastSelected.BackColor = SystemColors.Highlight;
            lastSelected.ForeColor = SystemColors.HighlightText;
        }

        /// <summary>
        /// Обработчик ухода курсора c дерева функций
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">EventArgs</param>
        private void FunctionTreeView_Leave(object sender, EventArgs e)
        {
            TreeNode lastSelected = null;
            if (sender == FunctionTreeView)
                lastSelected = lastSelectedFNode;

            if (lastSelected == null)
                return;

            lastSelected.BackColor = SystemColors.Highlight;
            lastSelected.ForeColor = SystemColors.HighlightText;
        }


        /// <summary>
        /// Обработчик после изменения названия узла дерева проекта
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">NodeLabelEditEventArgs</param>
        private void ProjectTreeView_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            // почему-то два раза для  ProjectData вызывается, причем второй раз e.Label == null
            if (e.Label != null)
                if (e.Node.Tag is ProjectData)
                    (e.Node.Tag as ProjectData).Name = e.Label;
                else if (e.Node.Tag is VirtFolder)
                {
                    (e.Node.Tag as VirtFolder).Name = "123";//e.Label;
                    //FillProjectTreeView(projectData);
                    //(e.Node.Tag as VirtFolder).Name = "223";//e.Label;
                }
            /*else if (e.Node.Tag is DocumentInfo)
                (e.Node.Tag as DocumentInfo).DocumentPath = PathUtility.ChangeFileName((e.Node.Tag as DocumentInfo).DocumentPath, e.Label);*/
        }

        private void PlantControlExplorer_Resize_1(object sender, EventArgs e)
        {
            this.Invalidate(true);
        }

        #endregion


        #region Properties' get/set event handlers
        /// <summary>
        /// Обработчик изменения значения свойства: должен изменить соответствующее поле
        /// объекта, свойство которого отображается, иначе изменение затронет лишь визуальную сторону
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">PropertySpecEventArgs</param>
        private void DmlProp_SetValue(Object sender, PropertySpecEventArgs e)
        {
            if (lastSelectedDMNode != null)
                switch (e.Property.Name)
                {
                    case "Комментарии":
                        if ((lastSelectedDMNode.Tag is NodeGroup) || (lastSelectedDMNode.Tag is Node))
                        {
                            this.DmlItemValueChanged(lastSelectedDM1Node.Tag, DmlEventCode.Comments, e.Value);
                        }
                        else if ((lastSelectedDMNode.Tag is Method) || (lastSelectedDMNode.Tag is NamedState))
                        {
                            this.DmlItemValueChanged(lastSelectedDMNode.Tag, DmlEventCode.Comments, e.Value);
                        }
                        break;

                    case "Управляется":
                        this.DmlItemValueChanged(lastSelectedDMNode.Tag, DmlEventCode.IsCompiled, e.Value);
                        break;

                }
        }

        /// <summary>
        /// Обработчик, позволяющий перекрыть отдачу значения читаемого свойства. 
        /// При отсутсвии этого обработчика или его бездействии в качестве читаемого
        /// выдастся последнее записанное в визуальный редактор значение
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">PropertySpecEventArgs</param>
        private void DmlProp_GetValue(Object sender, PropertySpecEventArgs e)
        {
            if (lastSelectedDMNode != null)
                switch (e.Property.Name)
                {
                    case "Комментарии":
                        if (lastSelectedDMNode.Tag is Method)
                            e.Value = (lastSelectedDMNode.Tag as Method).Comments;
                        else if (lastSelectedDMNode.Tag is NamedState)
                            e.Value = (lastSelectedDMNode.Tag as NamedState).Comments;
                        else if ((lastSelectedDMNode.Tag is Node) || (lastSelectedDMNode.Tag is NodeGroup))
                            e.Value = this.DmlItemValueRequested(lastSelectedDMNode.Tag, DmlEventCode.Comments);
                        break;
                    /*
                case "Управляется":
                    e.Value = this.DmlItemValueRequested(lastSelectedDMNode.Tag, DmlEventCode.IsCompiled);
                    break;
                     */
                    case "Имя":
                        if (lastSelectedDMNode.Tag is Method)
                            e.Value = (lastSelectedDMNode.Tag as Method).Name;
                        else if (lastSelectedDMNode.Tag is NamedState)
                            e.Value = (lastSelectedDMNode.Tag as NamedState).Name;
                        break;
                }


        }

        /// <summary>
        /// Обработчик изменения значения свойства: должен изменить соответствующее поле
        /// объекта, свойство которого отображается, иначе изменение затронет лишь визуальную сторону
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">PropertySpecEventArgs</param>
        private void ProjectProp_SetValue(Object sender, PropertySpecEventArgs e)
        {
            if (lastSelectedProjectNode != null)
                if (lastSelectedProjectNode.Tag is DocumentInfo)
                    switch (e.Property.Name)
                    {
                        case "Компилируется":
                            this.ProjectItemValueChanged(lastSelectedProjectNode.Tag, ProjectEventCode.IsDocCompiled, e.Value);
                            break;

                        case "Название":
                            this.ProjectItemValueChanged(lastSelectedProjectNode.Tag, ProjectEventCode.DocName, e.Value);
                            break;
                    }
                else if (lastSelectedProjectNode.Tag is ProjectData)
                    switch (e.Property.Name)
                    {
                        case "Название":
                            this.ProjectItemValueChanged(lastSelectedProjectNode.Tag, ProjectEventCode.ProjectName, e.Value);
                            break;
                    }
                else if (lastSelectedProjectNode.Tag is VirtFolder)
                    switch (e.Property.Name)
                    {
                        case "Название":
                            this.ProjectItemValueChanged(lastSelectedProjectNode.Tag, ProjectEventCode.VirtFoldName, e.Value);
                            break;
                    }
        }

        /// <summary>
        /// Обработчик, позволяющий перекрыть отдачу значения читаемого свойства. 
        /// При отсутсвии этого обработчика или его бездействии в качестве читаемого
        /// выдастся последнее записанное в визуальный редактор значение
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">PropertySpecEventArgs</param>
        private void ProjectProp_GetValue(Object sender, PropertySpecEventArgs e)
        {
            if (lastSelectedProjectNode != null)
                if (lastSelectedProjectNode.Tag is DocumentInfo)
                    switch (e.Property.Name)
                    {
                        case "Компилируется":
                            e.Value = this.ProjectItemValueRequested(lastSelectedProjectNode.Tag, ProjectEventCode.IsDocCompiled);
                            break;
                        case "Название":
                            e.Value = this.ProjectItemValueRequested(lastSelectedProjectNode.Tag, ProjectEventCode.DocName);
                            break;
                        case "Путь":
                            e.Value = PathUtility.MakePathLocal(Path.GetDirectoryName((lastSelectedProjectNode.Tag as DocumentInfo).DocumentPath), Locality.CurrentProjectDir);
                            break;
                        case "Тип":
                            e.Value = (lastSelectedProjectNode.Tag as DocumentInfo).DocumentType.Name;
                            break;
                    }
                else if (lastSelectedProjectNode.Tag is ProjectData)
                    switch (e.Property.Name)
                    {
                        case "Файл сцены":
                            e.Value = (lastSelectedProjectNode.Tag as ProjectData).DomainModelFilePath;
                            break;
                        case "Название":
                            e.Value = (lastSelectedProjectNode.Tag as ProjectData).Name;
                            break;
                        case "Путь":
                            e.Value = this.ProjectItemValueRequested(lastSelectedProjectNode.Tag, ProjectEventCode.ProjectPath);
                            break;
                        case "Тип":
                            e.Value = new ProjectTypeConverter().ConvertTo((lastSelectedProjectNode.Tag as ProjectData).ProjectType, typeof(string));
                            break;
                    }
                else if (lastSelectedProjectNode.Tag is VirtFolder)
                    switch (e.Property.Name)
                    {
                        case "Название":
                            e.Value = (lastSelectedProjectNode.Tag as VirtFolder).Name;
                            break;
                    }
        }
        #endregion


        /// <summary>
        /// Заменить в строке символы "//" на точки "."
        /// </summary>
        /// <param name="s">исходная строка</param>
        /// <returns>возвращаемая строка</returns>
        private string ChangePathOnPoints(string s)
        {
            char[] a = new char[s.Length];
            a = s.ToCharArray();
            int j = 0;
            while (a[j] != '\\')
                j++;
            string sss = new string(a);
            a = new char[s.Length - j - 1];
            sss.CopyTo(j + 1, a, 0, s.Length - j - 1);

            for (int i = 0; i < a.Length; i++)
                if (a[i] == '\\')
                    a[i] = '.';
            string ss = new string(a);
            return ss;
        }


        /// <summary>
        /// Распахнуть дерево проекта, кроме документов
        /// </summary>
        private void ExpandExceptDocuments()
        {
            foreach (var rootNode in ProjectTreeView.Nodes)
                rootNode.DeepWalk("Nodes",
                    (node) => { if ((((TreeNode)node).Nodes.Count != 0) && !(((TreeNode)node).Tag is DocumentInfo)) ((TreeNode)node).Expand(); });
        }


        private void ProjectTreeView_BeforeLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            /*ProjectTreeView.LabelEdit = false;
            FillProjectTreeView(projectData);*/
            /*var form = new Form();
            form.Text = "e.Node.Text" + e.Node.Text +", nodes3 ="+ ProjectTreeView.Nodes[0].Nodes[2].Text;
            form.Show();*/
        }

        /// <summary>
        /// Сворачивать и разворачивать узлы по двойному щелчку будем сами
        /// (тогда мы перед вызовом разрешим тогглинг)
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">TreeViewCancelEventArgs</param>
        private void ProjectTreeView_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            if (!mayNodeToggle)
                e.Cancel = true;
            else
                if ((e.Node.Tag is VirtFolder) || (e.Node.Tag is ProjectData))
                {
                    e.Node.ImageIndex = 0;
                    e.Node.SelectedImageIndex = 0;
                }

        }


        /// <summary>
        /// Сворачивать и разворачивать узлы по двойному щелчку будем сами
        /// (тогда мы перед вызовом разрешим тогглинг)
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">TreeViewCancelEventArgs</param>
        private void ProjectTreeView_BeforeCollapse(object sender, TreeViewCancelEventArgs e)
        {
            if (!mayNodeToggle)
                e.Cancel = true;
            else
                if ((e.Node.Tag is VirtFolder) || (e.Node.Tag is ProjectData))
                {
                    e.Node.ImageIndex = 1;
                    e.Node.SelectedImageIndex = 1;
                }
        }

        /// <summary>
        /// Обработчик на нажатие клавиши мыши
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">MouseEventArgs</param>
        private void ProjectTreeView_MouseDown(object sender, MouseEventArgs e)
        {
            TreeNode node = ProjectTreeView.GetNodeAt(e.Location);
            if (node != null)
            {
                Rectangle boundsWithIcon = node.Bounds;
                boundsWithIcon.X -= 16;
                if ((boundsWithIcon.Contains(e.Location)))
                    PrjTreeView_NodeMouseClick(sender, new TreeNodeMouseClickEventArgs(node, e.Button, e.Clicks, e.X, e.Y));

            }
        }

        /// <summary>
        /// Обработчик на событие передвижения мыши
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">MouseEventArgs</param>
        private void ProjectTreeView_MouseMove(object sender, MouseEventArgs e)
        {
            if ((e.Button == MouseButtons.Left) && (lastSelectedProjectNode != null) && ((lastSelectedProjectNode.Tag is DocumentInfo) || (lastSelectedProjectNode.Tag is VirtFolder)))
            {
                // Proceed with the drag-and-drop, passing in the list item.                    
                DragDropEffects dropEffect = ProjectTreeView.DoDragDrop(lastSelectedProjectNode, DragDropEffects.All);
            }
        }


        #region Drag'n'Drop event handlers

        /// <summary>
        /// Обработчик события: Drop 
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">DragEventArgs</param>
        private void ProjectTreeView_DragDrop(object sender, DragEventArgs e)
        {
            TreeNode node = ProjectTreeView.GetNodeAt(ProjectTreeView.PointToClient(new Point(e.X, e.Y)));
            if ((node != null) && (e.Data.GetDataPresent(typeof(TreeNode))))
            {
                switch (e.Effect)
                {
                    case DragDropEffects.Move:
                        if ((node.Tag is VirtFolder) || (node.Tag is ProjectData))
                        {
                            TreeNode copyNode = e.Data.GetData(typeof(TreeNode)) as TreeNode;
                            List<object> items = new List<object>();
                            if (copyNode.Tag is DocumentInfo)
                                items.Add((copyNode.Tag as DocumentInfo));
                            else if (copyNode.Tag is VirtFolder)
                                items.Add((copyNode.Tag as VirtFolder));
                            ProjectItemsDragDrooped(items, (node.Tag is VirtFolder ? node.Tag as VirtFolder : projectData.ProjectFolder));
                        }
                        break;
                }
            }
        }

        /// <summary>
        /// Обработчик события: принесли какие-то объекты
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">DragEventArgs</param>
        private void ProjectTreeView_DragEnter(object sender, DragEventArgs e)
        {
            if (!e.Data.GetDataPresent(typeof(TreeNode)))
                e.Effect = DragDropEffects.None;
        }

        /// <summary>
        /// Обработчик события: объекты Drag проносят над нами
        /// </summary>
        /// <param name="sender">sender</param>
        /// <param name="e">DragEventArgs</param>
        private void ProjectTreeView_DragOver(object sender, DragEventArgs e)
        {
            TreeNode destNode = ProjectTreeView.GetNodeAt(ProjectTreeView.PointToClient(new Point(e.X, e.Y)));
            if ((destNode != null) && (e.Data.GetDataPresent(typeof(TreeNode))))
            {
                TreeNode dataNode = e.Data.GetData(typeof(TreeNode)) as TreeNode;
                if (((destNode.Tag is VirtFolder) || (destNode.Tag is ProjectData)) && (dataNode.Tag != destNode.Tag))
                    e.Effect = DragDropEffects.Move;
                else e.Effect = DragDropEffects.None;
            }
        }
        #endregion


        #region to Close and Open ToolWindows and not to select SplitContainer after moving

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            pnlPropSaveSpDist = splitContainer1.SplitterDistance;
            splitContainer1.SplitterDistance = splitContainer1.Height;
            pnlProperties.Hide();
        }

        private void pnlProperties_VisibleChanged(object sender, EventArgs e)
        {
            if (pnlProperties.Visible == true)
                splitContainer1.SplitterDistance = pnlPropSaveSpDist;
        }


        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            splitContainer2.SplitterDistance = 0;
            pnlTabControl.Hide();
        }

        private void pnlTabControl_VisibleChanged(object sender, EventArgs e)
        {
            if (pnlTabControl.Visible == true)
                if (!pnlDmlTreeView2.Visible)
                    splitContainer2.SplitterDistance = splitContainer2.Height;
                else splitContainer2.SplitterDistance = splitContainer2.Height / 2;
        }

        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            if (splitContainer2.Panel2.Controls.Contains(pnlDmlTreeView2))
                splitContainer2.Panel2.Controls.Remove(pnlDmlTreeView2);
            splitContainer2.SplitterDistance = splitContainer2.Height;
            splitContainer2.IsSplitterFixed = true;
            pnlDmlTreeView2.Hide();
        }

        private void pnlDmlTreeView2_VisibleChanged(object sender, EventArgs e)
        {
            if (pnlDmlTreeView2.Visible == true)
            {
                if (!splitContainer2.Panel2.Controls.Contains(pnlDmlTreeView2))
                {
                    splitContainer2.Panel2.Controls.Add(pnlDmlTreeView2);
                    splitContainer2.FixedPanel = FixedPanel.Panel2;
                }
                if (!pnlTabControl.Visible)
                    splitContainer2.SplitterDistance = splitContainer2.Height;
                else splitContainer2.SplitterDistance = splitContainer2.Height / 2;
            }
        }

        private void splitContainer2_SplitterMoved(object sender, SplitterEventArgs e)
        {
            tabControl.Select();
        }

        private void splitContainer1_Panel1_Resize(object sender, EventArgs e)
        {
            this.Invalidate(true);
        }

        private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e)
        {
            this.tabControl.Select();
        }
        #endregion

    }
}